package org.campuscontent.main;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.DataInputStream;
import java.io.StringWriter;
import java.lang.reflect.Constructor;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JSplitPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.campuscontent.config.Config;
import org.campuscontent.io.Base64;
import org.campuscontent.io.PHPQuery;
import org.campuscontent.model.Automata;
import org.campuscontent.model.LObject;
import org.campuscontent.ui.AutomataEditor;
import org.campuscontent.ui.ComboRenderer;
import org.campuscontent.ui.ProblemCtrl;
import org.campuscontent.ui.TemplateBase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class MainFrame extends JApplet implements ActionListener, KeyListener
{
	public String userid;
	public String loidMain;

	public Automata automata;
	public LObject lobject;
	public AutomataApplet applet;
	public JSplitPane rootPanel;
	public AutomataEditor ae;
	public JSplitPane aeSplit;


	public ProblemCtrl problemCtrl;
	public JSplitPane aeInfo;
	public JSplitPane splitRight;

	public int templateID;
	public TemplateBase templateBase;
	private String createTempaletFrom;
	private String cbActionSource;
	private boolean studentView;
	// totoro
	public PHPQuery phpQuery;
	// totoro

	// Construct the frame
	public MainFrame( AutomataApplet automataApplet )
	{
		userid   = "public";
		loidMain = "-1";
		// totoro
		phpQuery = new PHPQuery(Config.REPOSITORY_SERVER);
		// totoro
		this.applet = automataApplet;
		createTempaletFrom = new String("");
		cbActionSource = new String("");
	}

	public void init()
	{
		ae = new AutomataEditor(true);
		problemCtrl = new ProblemCtrl(this);

		/*
		aeSplit = new JSplitPane();
		aeSplit.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
		aeSplit.setBorder(null);
		aeSplit.add(ae,JSplitPane.LEFT);
		aeSplit.setDividerSize(1);
		aeSplit.setDividerLocation(Config.POSITION_TO_HIDE_WRONG_AUTOMATA_EDITOR);
		aeSplit.setEnabled(false);
		*/

		aeInfo = new JSplitPane();
		
		aeInfo.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
		aeInfo.add( ae         , JSplitPane.LEFT  );
		aeInfo.add( problemCtrl, JSplitPane.RIGHT );
		
		aeInfo.setDividerSize(Config.DIVIDER_SIZE);
		aeInfo.setDividerLocation(Config.RIGHT_DIVIDER_LOCATION);
		aeInfo.setResizeWeight( 1 );
		aeInfo.setEnabled( true );
		aeInfo.setOneTouchExpandable( true );

		// paraDefault.setPreferredSize(new Dimension(600,85));

		// hide previous next submit solution buttons
		// paraDefault.setDividerLocation(1000);

		rootPanel = new JSplitPane();
		// teacher.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		rootPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
		
		// FIXME:  the templateBase component should be resizeable  ::  see ProblemCtrl::actionPerformed
		rootPanel.add( aeInfo, JSplitPane.TOP          );
		//rootPanel.add( templateBase, JSplitPane.BOTTOM );
		
		rootPanel.setDividerSize(Config.DIVIDER_SIZE);
		rootPanel.setBorder( null );
		rootPanel.setDividerLocation(Config.ROOT_HEIGHT);
		rootPanel.setResizeWeight(0.5);
		rootPanel.setPreferredSize(new Dimension(Config.ROOT_WIDTH,Config.ROOT_HEIGHT));
		rootPanel.setEnabled(false);
		
		getContentPane().setLayout(new BorderLayout());
		getContentPane().add(rootPanel, BorderLayout.CENTER);

				
		if (loidMain.equals("-1"))
		{
			newLObject();
		} else
		{
			if (!updateUIFromLObject())
			{
				loidMain ="-1";
				newLObject();
			}
		}

		if (userid.equals("-1"))
		{
			if (!updateUIFromLObject())
			{
				JOptionPane.showMessageDialog(getWindowForComponent(applet), "Specified automate does not exist, change to create new automate mode.");
				loidMain ="-1";
				newLObject();
			}
		}
		else
			setStudentView(false);
	}

	

	public boolean isStudentView()
	{
		return studentView;
	}

	public void setStudentView(boolean studentView)
	{
		this.studentView = studentView;
	}

	public void showStudentView()
	{
		this.problemCtrl.setPreview();
		this.problemCtrl.exitPreview.setVisible(false);
	}

	@SuppressWarnings("unchecked")
	public void newLObject()
	{
		lobject = new LObject();
		lobject.setLoid("-1");
		lobject.setTitle("configurable automata");
		lobject.setAid("-1");
		lobject.setOwner("public");
		ComboRenderer cbr = new ComboRenderer();
		lobject
				.setDesc(cbr.getItemAt(0));
		lobject.setTemplate("-1");
		lobject.setSolution("solution");
		lobject.setConfig("configure");

		automata = new Automata();
		automata.setId("-1");
		automata.setSource("-1");
		automata.setName("automata");
		automata.setGraphStr("");
		
		ae.setEnable(true);

		problemCtrl.lobjectTitle.setText(lobject.getTitle());
		problemCtrl.lobjectDescribtion.setText(lobject.getDesc());
		
		try
		{
			String str = "org.campuscontent.ui.Template1";
			templateID = 1;   
			Class classTemp = Class.forName(str);
			Constructor[] cons = classTemp.getDeclaredConstructors();
			Constructor con;
			for (int i = 0; i < cons.length; i++)
			{
				con = cons[i];
				System.out.println("constructor num: " + con.getParameterTypes().length );
				   if (con.getParameterTypes().length == 1) 
				   {
					   createTempaletFrom = "mf";
					   templateBase = (TemplateBase)con.newInstance(new Object[]{this });
						rootPanel.add(templateBase, JSplitPane.BOTTOM);
				   }				
			}
			problemCtrl.problemTemplate.setSelectedIndex(0);			

		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	@SuppressWarnings("unchecked")
	public boolean updateUIFromLObject()
	{
		if (!readLObjectFromDB()) return false;
		ae.loadGraphFromStr(automata.getGraphStr());
//		ae.setEnable(false);

		problemCtrl.lobjectTitle.setText(lobject.getTitle());
		problemCtrl.lobjectDescribtion.setText(lobject.getDesc());

		try
		{
			int intTemplate = Integer.parseInt(lobject.getTemplate());
			String str = "org.campuscontent.ui.Template" + intTemplate;
			templateID = intTemplate;
			Class classTemp = Class.forName(str);
			Constructor[] cons = classTemp.getDeclaredConstructors();
			Constructor con;
			for (int i = 0; i < cons.length; i++)
			{
				con = cons[i];
				   if (con.getParameterTypes().length == 1) 
				   {
					   templateBase = (TemplateBase)con.newInstance(new Object[]{this });
						rootPanel.add(templateBase, JSplitPane.BOTTOM);
				   }				
			}
			this.setCbActionSource("mf");
			problemCtrl.problemTemplate.setSelectedIndex(intTemplate-1);		
			templateBase.setParaConfig(lobject.getConfig());
			
		} catch (Exception e)
		{
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public boolean readLObjectFromDB()
	{
		// lobject
		String loid = ""; // id of lobject
		String aid = ""; // id of autmata bind to the lobject
		String title = ""; // name of a lobject
		String owner = ""; // owner of a lobject
		String desc = ""; // description of a lobject
		String solution = ""; // solution of a lobject
		String configure = ""; // configure of a lobject
		String template = ""; // template of a lobject

		String aname = ""; // name of a automata
		String graphStr = "";// graph data of automata
		String source = ""; // id of current automata id

		phpQuery.add("query_mode", Integer.toString(Config.PHP_QUERY_READ));
		phpQuery.add("id", loidMain);

		// Get the inputstream from the server
		try
		{
			DataInputStream dis = phpQuery.query();

			Element currentRoot, tmpElement;
			NodeList currentNodeList, currentTxtList;
			NodeList currentRootList;

			// Construct the document from the inputstream
			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(dis);

			// normalize text representation
			doc.getDocumentElement().normalize();
			
			// create string from xml tree
			
			TransformerFactory transfac = TransformerFactory.newInstance();
			Transformer trans;
			trans = transfac.newTransformer();

			trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
			trans.setOutputProperty(OutputKeys.INDENT, "yes");

			StringWriter sw = new StringWriter();
			StreamResult result = new StreamResult(sw);
			DOMSource sourceTest = new DOMSource(doc);
			try
			{
				trans.transform(sourceTest, result);
			} catch (TransformerException e)
			{
				e.printStackTrace();
				System.out.println("tranfoming from source have a problem");
			}
			String xmlString = sw.toString();
//			System.out.println(xmlString);

			// get root of document
			currentRootList = doc.getElementsByTagName("lobject");
			currentRoot = (Element) currentRootList.item(0);

			// get the lobject id
			currentNodeList = currentRoot.getElementsByTagName("id");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			loid = ((Node) currentTxtList.item(0)).getNodeValue().trim();
			if (loid.endsWith("none"))
			{
				JOptionPane.showMessageDialog(getWindowForComponent(applet), "Specified automate does not exist, change to create  a new automate mode.");
				return false;
			}
			// get the automata id
			currentNodeList = currentRoot.getElementsByTagName("aid");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			aid = ((Node) currentTxtList.item(0)).getNodeValue().trim();

			// get the source of automata
			currentNodeList = currentRoot.getElementsByTagName("source");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			source = ((Node) currentTxtList.item(0)).getNodeValue().trim();

			// get the name of automata
			currentNodeList = currentRoot.getElementsByTagName("aname");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			aname = ((Node) currentTxtList.item(0)).getNodeValue().trim();

			// get the name of automata
			currentNodeList = currentRoot.getElementsByTagName("gstring");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			graphStr = ((Node) currentTxtList.item(0)).getNodeValue().trim();
			graphStr = new String(Base64.decode(graphStr));

			// get the name of lobject
			currentNodeList = currentRoot.getElementsByTagName("title");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			title = ((Node) currentTxtList.item(0)).getNodeValue().trim();

			// get the owner of lobject
			currentNodeList = currentRoot.getElementsByTagName("owner");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			owner = ((Node) currentTxtList.item(0)).getNodeValue().trim();

			// get the description of lobject
			currentNodeList = currentRoot.getElementsByTagName("desc");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			desc = ((Node) currentTxtList.item(0)).getNodeValue().trim();
			desc = new String(Base64.decode(desc));

			// get the solution fo lobject
			currentNodeList = currentRoot.getElementsByTagName("solution");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			solution = ((Node) currentTxtList.item(0)).getNodeValue().trim();
			solution = new String(Base64.decode(solution));


			// get the template of lobject
			currentNodeList = currentRoot.getElementsByTagName("template");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			template = ((Node) currentTxtList.item(0)).getNodeValue().trim();

			// get the configure of lobject
			currentNodeList = currentRoot.getElementsByTagName("configure");
			tmpElement = (Element) currentNodeList.item(0);
			currentTxtList = tmpElement.getChildNodes();
			configure = ((Node) currentTxtList.item(0)).getNodeValue().trim();

			lobject = new LObject(loid, title, aid, owner, desc, template,
					configure, solution);
			automata = new Automata(aid, source, graphStr, aname);

		} catch (SAXParseException err)
		{
			System.out.println("** Parsing error" + ", line "
					+ err.getLineNumber() + ", uri " + err.getSystemId());
			System.out.println(" " + err.getMessage());
			return false;
		} catch (SAXException e)
		{
			Exception x = e.getException();
			((x == null) ? e : x).printStackTrace();
			return false;
		} catch (Throwable t)
		{
			t.printStackTrace();
			JOptionPane.showMessageDialog(getWindowForComponent(applet), "No route to server, change to local use mode.");
			return false;
		}
		return true;
	}

	public void updateToLObjectNew()
	{
		if (this.loidMain.equals("-1"))
		{
			lobject.setLoid("-1");
			lobject.setTitle(problemCtrl.lobjectTitle.getText().trim());
			lobject.setAid("-1");
			lobject.setOwner(userid);
			lobject.setDesc(this.problemCtrl.lobjectDescribtion.getText());
			lobject.setTemplate(Integer.toString(templateID));
			// lobject.setSolution("");
			// lobject.setConfig("");

			automata.setId("-1");
			automata.setSource("-1");
			// automata.setName("");

			automata.setGraphStr( ae.getGraphAsString() );
		} else
		{
			lobject.setTitle(problemCtrl.lobjectTitle.getText().trim());
			lobject.setDesc(this.problemCtrl.lobjectDescribtion.getText());
			lobject.setTemplate(Integer.toString(templateID));
			// lobject.setSolution("");
			// lobject.setConfig("");

			automata.setGraphStr( ae.getGraphAsString() );
		}
	}

	public void updateToLObjectOverride()
	{
		lobject.setLoid(loidMain);
		lobject.setTitle(problemCtrl.lobjectTitle.getText().trim());
		// lobject.setAid();
		lobject.setOwner(userid);
		lobject.setDesc(this.problemCtrl.lobjectDescribtion.getText());
		lobject.setTemplate(Integer.toString(templateID));
		// lobject.setSolution("");
		// lobject.setConfig("");

		// automata.setId("-1");
		automata.setSource(automata.getId());
		automata.setGraphStr( ae.getGraphAsString() );

	}

	public JSplitPane getRootSplitPane()
	{
		return rootPanel;
	}

	public static void main(String[] args)
	{
        System.setProperty( "org.campuscontent.persistence.debug", "true" );
        
        createAndShowGUI();
	}

	public static void createAndShowGUI()
	{
        // Create and set up the window.
        JFrame frame = new JFrame( "Automata" );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        MainFrame mf = new MainFrame( null );
        frame.getContentPane().add( mf );

        // Display the window.
        frame.pack();
        frame.setVisible( true );
	}

	public void actionPerformed(ActionEvent event)
	{
		String cmd = event.getActionCommand();

		if (cmd.equals("Edit"))
		{
			// this.problemCtrl.remove(2);
			// this.problemCtrl.add(this.problemCtrl.exitPreview);
			// this.problemCtrl.repaint();
			// this.splitRight.remove(2);
			// this.splitRight.add(paraExample1,JSplitPane.BOTTOM);
			// this.splitRight.setDividerLocation(Config.TOP_BOTTOM_DIVIDER_LOCATION);
			// this.splitRight.repaint();
		}

		// totoro

		// Get the event source
		Object evtSrc = event.getSource();

		if (evtSrc instanceof JComboBox)
		{

			JComboBox comboSrc = (JComboBox) evtSrc;

			// Get the selected item

			String sel = Integer.toString(comboSrc.getSelectedIndex() + 1);

			phpQuery.add("peda_mode", sel);

			// try{
			// // String[] result = {phpQuery.query()};
			// //// phpQuery.query();
			// // JList excListPublic = teacher.getPublicExcList();
			// // excListPublic.removeAll();
			// //
			// // excListPublic.setListData(result);
			//				
			// }catch (IOException e){
			//				
			// }

		}
	}

	public void setParametPanel(int added)
	{
		this.splitRight.remove(2);

		switch (added)
		{
		case 1:
			// hide previous next submit solution buttons
			templateBase.setDividerLocation(1000);
			this.splitRight.add(templateBase, JSplitPane.BOTTOM);
			break;

		case 2:
//			// hide previous next submit solution buttons
//			template2.setDividerLocation(1000);
//			this.splitRight.add(template2, JSplitPane.BOTTOM);
			break;

		default:
			// hide previous next submit solution buttons
			templateBase.setDividerLocation(1000);
			this.splitRight.add(templateBase, JSplitPane.BOTTOM);
			break;
		}

		this.splitRight.setDividerLocation(Config.POSITION_TO_SHOW_TEMPLATE);
		this.splitRight.repaint();

	}

	public void keyTyped(KeyEvent e)
	{
	}

	public void keyReleased(KeyEvent e)
	{
	}

	public void keyPressed(KeyEvent e)
	{
	}

	public Frame getWindowForComponent(Component parentComponent)
	{
		if (parentComponent instanceof Frame)
			return (Frame) parentComponent;
		return getWindowForComponent(parentComponent.getParent());
	}

	public String getCreateTempaletFrom()
	{
		return createTempaletFrom;
	}

	public void setCreateTempaletFrom(String createTempaletFrom)
	{
		this.createTempaletFrom = createTempaletFrom;
	}

	public String getCbActionSource()
	{
		return cbActionSource;
	}

	public void setCbActionSource(String cbActionSource)
	{
		this.cbActionSource = cbActionSource;
	}
	
	public Frame getFrame()
	{
		Container parent;
		for (parent = applet; parent != null && !(parent instanceof Frame); parent = parent.getParent())
			;
		if (parent != null)
			return (Frame) parent;
		else
			return null;
	}
	
}
